package com.tt5.services.vertx.handlers.failure

import com.tt5.services.error.ApiException
import com.tt5.services.vertx.requestToString
import io.netty.handler.codec.http.HttpResponseStatus
import io.vertx.core.Handler
import io.vertx.core.impl.logging.Logger
import io.vertx.core.impl.logging.LoggerFactory
import io.vertx.ext.web.RoutingContext
import io.vertx.kotlin.core.json.json
import io.vertx.kotlin.core.json.jsonObjectOf

/**
 * 通用的失败处理器，可在具体route中通过[handler]实现自定义处理
 */
class FailureHandler(
  /**
   * 自定义失败处理
   * @return true：该失败响应已消费，false：该失败响应由通用的失败处理器继续处理
   */
  val handler: ((RoutingContext) -> Boolean)? = null
) : Handler<RoutingContext> {
  val logger: Logger = LoggerFactory.getLogger(javaClass.name)

  override fun handle(ctx: RoutingContext) {
    val failure = try {
      if (handler?.invoke(ctx) == true) return
      ctx.failure()
    } catch (e: Throwable) {
      e
    }
    if (failure is ApiException) {
      if (failure.code >= HttpResponseStatus.INTERNAL_SERVER_ERROR.code())
        logger.error("request: ${ctx.requestToString()} failed: ${failure.stackTraceToString()}")
      else logger.info("failed: ${failure.message}")
      ctx.response().statusCode = failure.code
      ctx.json(
        jsonObjectOf(
          "code" to failure.error,
          "message" to failure.content
        )
      )
    } else {
      logger.error(
        "failure ${ctx.statusCode()}\r request: ${ctx.requestToString()} error: ${failure?.stackTraceToString()}"
      )
      ctx.response().statusCode = ctx.statusCode()
      ctx.json(
        jsonObjectOf(
          "code" to ctx.statusCode(),
          "message" to "服务器内部错误"
        )
      )
//      ctx.response().setStatusCode(ctx.statusCode()).putHeader(
//        "content-type", "text/plain; charset=utf-8"
//      ).end(
//        "Error: ${failure?.stackTraceToString() ?: "Unknown"}"
//      )
    }
  }
}
